package org.blackcat.core.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.blackcat.common.StringUtils;
import org.blackcat.core.annotation.RedisCache;
import org.blackcat.dao.redis.RedisHandle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by Duo Duo on 2017/1/9.
 */
@Component
@Aspect
public class CacheAdvice implements Ordered{

    @Autowired
    private RedisHandle redisHandle;

    @Pointcut("@annotation(org.blackcat.core.annotation.RedisCache)")
    public void redisCacheAdvice(){}

    @Around("redisCacheAdvice()")
    public Object redisCache(ProceedingJoinPoint pjp) throws Throwable {
        Object obj = null;
        String key = getKey(pjp);
        String rs = redisHandle.getString(key);
        Signature signature = pjp.getSignature();
        MethodSignature msig = (MethodSignature)signature;
        Method method = pjp.getTarget().getClass().getMethod(msig.getName(),msig.getParameterTypes());
        if(StringUtils.isNullOrEmpty(rs) || rs.contains(":null")){
            obj = pjp.proceed();
             RedisCache redisCache = method.getAnnotation(RedisCache.class);
            int minite = redisCache.value();
            rs = JSON.toJSONString(obj);
            redisHandle.setString(key,rs,minite);
        }else{
            Class clazz = method.getReturnType();
            obj = JSON.parseObject(rs,clazz);
        }
        return obj;
    }

    private String getKey(ProceedingJoinPoint pjp){
        StringBuffer keyBuffer = new StringBuffer();
        keyBuffer.append(pjp.getSignature().getDeclaringTypeName()+pjp.getSignature().getName());
        for(Object obj : pjp.getArgs()){
            keyBuffer.append(obj.getClass().getName());
            if(obj instanceof String){
                keyBuffer.append(obj.toString());
                return keyBuffer.toString();
            }
            Field[] fields = obj.getClass().getDeclaredFields();
            for(Field field : fields){
                field.setAccessible(true);
                try {
                    keyBuffer.append(field.get(obj));
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return keyBuffer.toString();
    }

    @Override
    public int getOrder() {
        return 0;
    }

}
